import { NestFactory } from '@nestjs/core';
import { ValidationPipe } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger';
import { knife4jSetup } from 'nest-knife4j';

// 热模块替换类型定义
interface NodeModule {
  hot?: {
    accept: () => void;
    dispose: (callback: () => void) => void;
  };
}

// 热模块替换处理
declare const module: NodeModule | undefined;

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // 获取配置服务
  const configService = app.get(ConfigService);

  // 配置Swagger
  const configSwagger = new DocumentBuilder()
    .setTitle('API文档')
    .setDescription('API接口文档')
    .setVersion('1.0')
    .addTag('api')
    .build();

  // 创建Swagger文档，注意这里的路径要和Knife4j配置对应
  const document = SwaggerModule.createDocument(app, configSwagger);
  // 这里将Swagger JSON文档路径设置为`/api-docs-json`
  SwaggerModule.setup('api-docs-json', app, document);

  // 配置knife4j，修复路径问题
  knife4jSetup(app, [
    {
      name: 'Knife4j API 文档',
      url: '/api-docs-json', // 直接使用Swagger的JSON输出路径
      swaggerVersion: '2.0',
      location: '/api-docs-json', // 对应Swagger的setup路径
    },
  ]);

  // 配置全局验证管道
  app.useGlobalPipes(
    new ValidationPipe({
      whitelist: true, // 自动移除未在DTO中定义的属性
      forbidNonWhitelisted: true, // 当请求中包含未在DTO中定义的属性时抛出错误
      transform: true, // 自动将请求参数转换为DTO实例
    }),
  );

  // 使用ConfigService获取端口号
  await app.listen(configService.get('PORT', 3000));

  console.log(`Application is running on: ${await app.getUrl()}`);
  console.log(`Swagger JSON文档: ${await app.getUrl()}/api-docs-json`);
  console.log(`Knife4j文档地址: ${await app.getUrl()}/doc.html`);

  // 启用热模块替换
  if (module?.hot) {
    module.hot.accept();
    module.hot.dispose(() => {
      void app.close().catch((err) => {
        console.error('Error during app shutdown:', err);
      });
    });
  }
}

// 处理bootstrap函数返回的Promise
void (async () => {
  try {
    await bootstrap();
  } catch (error) {
    console.error('Error during application startup:', error);
    process.exit(1);
  }
})();
